unit BrowseControl;

interface
type
  TStateType = (stBrowse, stLookup);
  TSetValue = procedure(value: TAbstractModel) of object;

  TBrowswForm = class(TForm)
  private
    FState: TStateType;
  protected
    procedure SetState(value: TStateType); virtual;
  public
    procedure LookupOnChange(Sender: TObject); virtual; abstract;
    procedure GetValue(value: TAbstractModel); virtual; abstract;
    procedure SetSize; virtual; abstract;
    property State: TStateType read FState write SetState;

  end;

  TLookupControl = class(TObject)
  private
    FModel: TAbstractModel;
    FDAO: TAbstractDAO;
    FOnDropDown: TNotifyEvent;
    FOnKeyDown: TKeyEvent;
    FOnExit: TNotifyEvent;
    FOnChange: TNotifyEvent;

    FHostControl: TWinControl;
    FHostForm: TForm;
    FDockForm: TBrowswForm;
    FBrowseControl: TWinControl;

    FHostFormKeyPreview: Boolean;
    FHostFormKeyDown: TKeyEvent;

    FSetValue: TSetValue;
  protected
    procedure SetModel(value: TAbstractModel);
//    procedure SetDAO(value: TAbstractDAO);

    procedure LookupOnkeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure LookupOnExit(Sender: TObject);
    procedure LookupOnChange(Sender: TObject);
    procedure Close;
    function FindBrowseControl(value: TWinControl): TWinControl;
    procedure SetVisible(MainControl: tform; VisibleControl: twincontrol);
//    procedure SetBrowControlOnExit;
  public
    function Lookup(HostControl: TWinControl; HostForm: TForm; DockForm: TBrowswForm; setvalue: TSetValue): boolean;
    property Model: TAbstractModel read FModel write SetModel;
//    property DAO: TAbstractDAO read FDAO write SetDAO;
    destructor destroy; override;
  end;
implementation

procedure TBrowswForm.SetState(value: TStateType);
begin
  FState := value;
end;

///////////TLookupControl
procedure TLookupControl.SetModel(value: TAbstractModel);
begin
  if FModel <> nil then
  begin
    FreeAndNil(FModel);
  end;
  FModel := value.clone;
end;

function TLookupControl.FindBrowseControl(value: TWinControl): TWinControl;
var
  c1: twincontrol;
  i: integer;
begin
  result := nil;
  for i := 0 to value.ControlCount - 1 do
  begin
    if value.Controls[i] is TWinControl then
    begin
      c1 := value.Controls[i] as TwinControl;
      if (c1 is TDBGrid) or (c1 is TDBGridEh) or (c1 is TTreeView) then
      begin
        result := c1;
        exit;
      end;
      if c1.ControlCount > 0 then
      begin
        result := FindBrowseControl(c1);
        if result <> nil then exit;
      end;
    end;
  end;
end;

procedure TLookupControl.SetVisible(MainControl: tform; VisibleControl: twincontrol);
var
  i: integer;
  pc: TWinControl;
  procedure SetAllInvisible(MControl: TWincontrol);
  var
    c1: twincontrol;
    i: integer;
  begin
    for i := 0 to MControl.ControlCount - 1 do
    begin
      if MControl.Controls[i] is TWinControl then
      begin
        c1 := MControl.Controls[i] as TWinControl;
        (c1 as TwinControl).Visible := False;
        if c1.ControlCount > 0 then
        begin
          SetAllInvisible(c1);
        end;
      end;
    end;
  end;
begin
  SetAllInvisible(MainControl);
  VisibleControl.Visible := true;
  pc := VisibleControl.Parent;
  while pc <> MainControl do
  begin
    pc.Visible := true;
    pc := pc.Parent;
  end;
end;


{procedure TLookupControl.SetDAO(value: TAbstractDAO);
begin
  FDAO := value;
end;}

function TLookupControl.Lookup(HostControl: TWinControl; HostForm: TForm; DockForm: TBrowswForm; setvalue: TSetValue):
  boolean;
var
  pa: TPanel;
begin
  FHostControl := HostControl;
  FHostForm := HostForm;
  FDockForm := DockForm;
  FSetValue := SetValue;
  FBrowseControl := FindBrowseControl(FDockForm);

  FOnDropDown := (HostControl as TComboBox).OnDropDown;
  FOnKeyDown := (HostControl as TComboBox).OnKeyDown;

  FOnExit := (Hostcontrol as TComboBox).OnExit;
  FOnChange := (Hostcontrol as TComboBox).OnChange;

  FHostFormKeyPreview := FHostForm.KeyPreview;
  FHostFormKeyDown := FHostForm.OnKeyDown;

  (HostControl as TComboBox).OnDropDown := nil;
  (HostControl as TComboBox).OnKeyDown := self.LookupOnkeyDown;

  (HostControl as TComboBox).Onexit := self.LookupOnExit;
  (HostControl as TComboBox).OnChange := DockForm.LookupOnChange;

  FHostForm.KeyPreview := true;
  FHostForm.OnKeyDown := self.LookupOnkeyDown;

  if FBrowseControl is TDBGrid then
  begin
    (FBrowseControl as TDBGrid).OnExit := self.LookupOnExit;
    (FBrowseControl as TDBGrid).ReadOnly := true;
//    (FBrowseControl as TDBGrid).OnKeyDown := self.LookupOnkeyDown;
  end else
    if FBrowseControl is TDBGridEh then
    begin
      (FBrowseControl as TDBGridEh).OnExit := self.LookupOnExit;
      (FBrowseControl as TDBGridEh).ReadOnly := true;
//      (FBrowseControl as TDBGridEh).OnKeyDown := self.LookupOnkeyDown;
    end else
      if FBrowseControl is TTreeView then
      begin
        (FBrowseControl as TTreeView).OnExit := self.LookupOnExit;
        (FBrowseControl as TTreeView).ReadOnly := true;
//        (FBrowseControl as TTreeView).OnKeyDown := self.LookupOnkeyDown;
      end;

  SetVisible(FDockForm, FBrowseControl);

  FDockForm.State := stLookup;

  FDockForm.SetSize;
  AdjustEmbeddedForm(DockForm, hostcontrol, HostForm);
  FDockForm.Parent := HostForm;
  FDockForm.Visible := true;
  FDockForm.BorderStyle := bsnone;


end;

procedure TLookupControl.LookupOnChange(Sender: TObject);
begin
end;

procedure TLookupControl.LookupOnkeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  if sender = FHostControl then
    SendMessage(FBrowseControl.Handle, WM_KEYDOWN, Key, 0);

  if key = 13 then
  begin
//    FDAO.Retrieve(FModel, FDockForm.DataSet);
    FDockForm.GetValue(Fmodel);
    self.FSetValue(FModel);
  end;
  if (key = 13) or (Key = 27) then
  begin
    key := 0;
    self.close;
  end;
end;

procedure TLookupControl.LookupOnExit(Sender: TObject);
var
  i: integer;
  function IsActiveSelf(control: twincontrol): boolean;
  var
    control1: TWincontrol;
  begin
    control1 := control;
    result := false;
    while control1 <> nil do
    begin
      if control1 = FDockForm then
      begin
        result := true;
        exit;
      end;
      control1 := control1.Parent;
    end;
  end;
begin
  if FDockForm.FState = stLookup then
    if not IsActiveSelf(FHostForm.ActiveControl) then
      FHostcontrol.SetFocus;
end;

procedure TLookupControl.Close;
begin

  FHostForm.KeyPreview := FHostFormKeyPreview;
  FHostForm.OnKeyDown := FHostFormKeyDown;
  if FBrowseControl is TDBGrid then
  begin
    (FBrowseControl as TDBGrid).OnExit := nil;
    (FBrowseControl as TDBGrid).ReadOnly := true;
    (FBrowseControl as TDBGrid).OnKeyDown := nil;
  end else
    if FBrowseControl is TDBGridEh then
    begin
      (FBrowseControl as TDBGridEh).OnExit := nil;
      (FBrowseControl as TDBGridEh).ReadOnly := true;
      (FBrowseControl as TDBGridEh).OnKeyDown := nil;
    end else
      if FBrowseControl is TTreeView then
      begin
        (FBrowseControl as TTreeView).OnExit := nil;
        (FBrowseControl as TTreeView).ReadOnly := true;
        (FBrowseControl as TTreeView).OnKeyDown := nil;
      end;

  (FHostControl as TComboBox).OnDropDown := FOnDropDown;
  (FHostControl as TComboBox).OnKeyDown := FOnKeyDown;

  (FHostControl as TComboBox).OnExit := FOnExit;
  (FHostControl as TComboBox).OnChange := FOnChange;

  FDockForm.Visible := false;
  FDockForm.Parent := nil;
  FDockForm.Free;

  self.free;
end;

destructor TLookupControl.destroy;
begin
  if FModel <> nil then
    FModel.Free;
  inherited;
end;

end.

